package net.realsee.gcl.service.impl;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.realsee.common.constant.GclCcsConstants;
import net.realsee.common.enums.wcs.charact.WcsCharactEnum;
import net.realsee.common.exception.ccs.GclCcsTaskException;
import net.realsee.domain.wcs.data.bo.WcsUnitCharactBo;
import net.realsee.gcl.domain.bo.ccs.GclCcsLocationPosFixResult;
import net.realsee.gcl.domain.bo.ccs.GclCcsRequestParams;
import net.realsee.gcl.domain.bo.wcs.ContainerPositionBo;
import net.realsee.gcl.service.IGclCcsService;
import net.realsee.gcl.service.IGclLocationExtendService;
import net.realsee.service.wcs.data.IWcsZoneService;
import net.realsee.service.wcs.warehouse.IWcsWarehouseLocationService;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;

/**
 * 协鑫CCS接口实现
 *
 * @author:
 * @date: 2023/08/28 上午 10:13
 **/
@Slf4j
@RequiredArgsConstructor
@Service
public class GclCcsServiceImpl implements IGclCcsService {

    private final IWcsWarehouseLocationService iWcsWarehouseLocationService;
    private final IWcsZoneService iWcsZoneService;
    private final IGclLocationExtendService locationExtendService;

    /**
     * 上报CCS系统中库位可用状态
     */
    @Override
    public void reportCcsLocationStatus(GclCcsRequestParams requestParams) {
        locationExtendService.setCcsLocationStatus(requestParams.getLocation(), requestParams.getStatus());
    }

    /**
     * 查询WCS系统中库位任务状态
     */
    @Override
    public void queryWcsLocationTaskStatus(GclCcsRequestParams requestParams) {
        Integer wcsLocationTaskStatus = locationExtendService.getWcsLocationTaskStatus(requestParams.getLocation());
        if (ObjectUtil.notEqual(wcsLocationTaskStatus, requestParams.getType())) {
            throw new GclCcsTaskException(StrUtil.format("当前库位状态为{}", wcsLocationTaskStatus));
        }
    }

    /**
     * 上报CCS系统中库位内容器位置偏差数据
     */
    @Override
    public void reportContainerPosition(GclCcsRequestParams requestParams) {
        locationExtendService.setCcsLocationContainerPosition(
            ContainerPositionBo.builder()
                .location(requestParams.getLocation())
                .ccsPositionStatus(requestParams.getCode())
                .x1Sen01Val(requestParams.getX1_sen01_val())
                .x1Sen02Val(requestParams.getX1_sen02_val())
                .y1Sen01Val(requestParams.getY1_sen01_val())
                .y1Sen02Val(requestParams.getY1_sen02_val())
                .build());

        if (!StrUtil.equalsIgnoreCase(GclCcsConstants.OK,
            locationExtendService.getWcsLocationContainerPositionAdjustStatus(requestParams.getLocation()))) {
            throw new GclCcsTaskException("容器未调整到位");
        }
    }

    /**
     * 计算出容器待调整的位置值
     */
    @Override
    public GclCcsLocationPosFixResult calculatePositionToBeAdjusted(String location, String taskCode) {
        GclCcsLocationPosFixResult result = GclCcsLocationPosFixResult.builder().isValid(false).build();

        ContainerPositionBo containerPosition = locationExtendService.getCcsLocationContainerPosition(location);
        log.info("[二次定位][{}][{}]，容器调整前位置信息：{}", location, taskCode, JSONUtil.toJsonStr(containerPosition));
        if (ObjectUtil.isNull(containerPosition)) {
            log.error("[二次定位][{}][{}]，容器位置未推送。", location, taskCode);
            return result;
        }

        Integer x1 = containerPosition.getX1Sen01Val();
        Integer x2 = containerPosition.getX1Sen02Val();
        Integer y1 = containerPosition.getY1Sen01Val();
        Integer y2 = containerPosition.getY1Sen02Val();

        // 清洗上机，读取到无效值时处理方式。（甲方要求这样做的，肯定会有问题）(测距有效值200mm-400mm/600mm)
        if (StrUtil.startWithIgnoreCase(location, "04QXSJ")) {
            if (Math.abs(x1) > 150 || Math.abs(x2) > 150 || Math.abs(y1) > 150 || Math.abs(y2) > 150) {
                log.error("[二次定位][{}][{}]，容器位置推送错误。X1={} X2={} Y1={} Y2={}", location, taskCode, x1, x2, y1, y2);
                return result;
            }
        }

        // 脱胶上机，读取到无效值时处理方式。（甲方要求这样做的，肯定会有问题）(测距有效值70mm-130mm)
        if (StrUtil.startWithIgnoreCase(location, "04TJSJ")) {
            if (Math.abs(x1) == 31 || Math.abs(x2) == 31 || Math.abs(y1) == 31 || Math.abs(y2) == 31) {
                if (Math.abs(x1) == 31 && Math.abs(x2) == 31) {
                    log.warn("[二次定位][{}][{}]，容器位置推送错误。X1={} X2={}，强制都修改为-5。", location, taskCode, x1, x2);
                    x1 = -5;
                    x2 = -5;
                } else if (Math.abs(x1) == 31) {
                    log.warn("[二次定位][{}][{}]，容器位置推送错误。X1={}，强制修改为{}。", location, taskCode, x1, x2);
                    x1 = x2;
                } else if (Math.abs(x2) == 31) {
                    log.warn("[二次定位][{}][{}]，容器位置推送错误。X2={}，强制修改为{}。", location, taskCode, x2, x1);
                    x2 = x1;
                }

                if (Math.abs(y1) == 31 && Math.abs(y2) == 31) {
                    if (StrUtil.equalsAnyIgnoreCase(location, "04TJSJ001", "04TJSJ003")) {
                        log.warn("[二次定位][{}][{}]，容器位置推送错误。Y1={} Y2={}，强制都修改为-5。", location, taskCode, y1, y2);
                        y1 = -5;
                        y2 = -5;
                    } else {
                        log.warn("[二次定位][{}][{}]，容器位置推送错误。Y1={} Y2={}，强制都修改为5。", location, taskCode, y1, y2);
                        y1 = 5;
                        y2 = 5;
                    }
                } else if (Math.abs(y1) == 31) {
                    log.warn("[二次定位][{}][{}]，容器位置推送错误。Y1={}，强制修改为{}。", location, taskCode, y1, y2);
                    y1 = y2;
                } else if (Math.abs(y2) == 31) {
                    log.warn("[二次定位][{}][{}]，容器位置推送错误。Y2={}，强制修改为{}。", location, taskCode, y2, y1);
                    y2 = y1;
                }

                // 只调整X Y，不调整角度
                Integer calX = (x1 + x2) / 2;
                Integer calY = (y1 + y2) / 2;
                result.setIsValid(true).setXFix(calX).setYFix(calY).setAngle(0);
                log.info("[二次定位][{}][{}]，容器需调整偏差为：X={} Y={} ANGLE={}", location, taskCode, calX, calY, 0);
                return result;
            }
        }

        Integer calX = (x1 + x2) / 2;
        Integer calY = (y1 + y2) / 2;

        // X轴 Y轴方向两个传感器之间的距离
        BigDecimal xSensorDistance = BigDecimal.ZERO;
        BigDecimal ySensorDistance = BigDecimal.ZERO;
        // 根据库位查所在库位上的传感器之间的距离
        List<WcsUnitCharactBo> sensorDistanceList = iWcsWarehouseLocationService.getSensorDistance(location);
        if (ObjectUtil.isEmpty(sensorDistanceList)) {
            // 根据库位获取区域上的传感器之间的距离
            sensorDistanceList = iWcsZoneService.getZoneSensorDistanceList(location);
        }
        for (WcsUnitCharactBo data : sensorDistanceList) {
            if (data.getCharact().equals(WcsCharactEnum.X_SENSOR_DISTANCE.getCode())) {
                xSensorDistance = data.getTargetValue();
            } else if (data.getCharact().equals(WcsCharactEnum.Y_SENSOR_DISTANCE.getCode())) {
                ySensorDistance = data.getTargetValue();
            }
        }
        // 判断是否获取到传感器的距离
        if (NumberUtil.equals(xSensorDistance, BigDecimal.ZERO) || NumberUtil.equals(ySensorDistance, BigDecimal.ZERO)) {
            log.error("[二次定位][{}][{}]，XY轴传感器间距未设定。", location, taskCode);
            return result;
        }

        // 计算需要调整的角度
        double tanValue = (double) (y1 - y2) / ySensorDistance.intValue();
        double angle = Math.toDegrees(Math.atan(tanValue));
        // 乘以1000取整
        int calAngle = NumberUtil.mul(new BigDecimal(angle), 1000).setScale(0, RoundingMode.UP).intValue();

        result.setIsValid(true).setXFix(calX).setYFix(calY).setAngle(calAngle);
        log.info("[二次定位][{}][{}]，容器需调整偏差为：X={} Y={} ANGLE={}", location, taskCode, calX, calY, calAngle);
        return result;
    }

}
